#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h> 

#include "log.hpp"
#include "Protocol.hpp"



namespace Server
{
    // using namespace std;

    static const uint16_t gport = 8080;
    static const int gbacklog = 5;

    // const Request& req 输入性参数 | Response& resp 输出型参数
    typedef function<bool(const Request& req,Response& resp)> func_t;

    void handlerEnter(int sock,func_t func)
    {
        string inbuffer;
        while(true)
        {
            // 1.读取数据 "content_len"\r\n"x op y"\r\n
            // 1.1保证读到的是完整的请求
            string req_text,req_str;

            // 1.2 到这 req_text里面一定是一个完整的请求："content_len"\r\n"x op y"\r\n
            if(!recvPackage(sock,inbuffer,&req_text))   //读取一个完整的请求
                return;
            // cout << "带报头的请求：\n" << req_text << endl;
            if(!deLength(req_text,&req_str))    //去掉报头
                return;
            // cout << "去掉报头的正文：" << req_str << endl;
                
            // 2.反序列化
            // 2.1得到一个结构化的对象
            Request req;
            if(!req.deserialize(req_str))  
                return;

            // 3.进行处理
            // 3.1得到一个结构化的响应
            Response resp;
            func(req,resp);  //req的处理结果，全部放到了resp中

            // 4.对响应的Response 进行序列化
            // 4.1得到一个  "字符串"
            string resp_str;
            resp.serialize(&resp_str);
            // cout << "计算完成，对响应进行序列化：" << resp_str << endl;
            // 5.发送响应
            // 5.1 构建一个完整的报文
            string send_string = enLength(resp_str);
            // cout << "构建完整的报文：\n" << send_string << endl;
            send(sock,send_string.c_str(),send_string.size(),0);    //发送
        }
    }

    class calServer
    {
    public:
        calServer(const uint16_t& port = gport)
            :_listensock(-1),_port(port)
        {}
        void initServer()
        {
            //1.创建socket文件套接字对象
            _listensock = socket(AF_INET,SOCK_STREAM,0);
            if(_listensock < 0)
            {
                logMessage(FATAL,"create socket error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL,"create socket success: %d",_listensock);

            // 2.bind 绑定自己的网络信息
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;
            if(bind(_listensock,(struct sockaddr*)&local,sizeof(local)) < 0)
            {
                logMessage(FATAL,"bind socket error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL,"bind socket success");

            //3. 设置socket为监听状态
            if(listen(_listensock,gbacklog) < 0)
            {
                logMessage(FATAL,"listen socket error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL,"listen socket success");


        }
        void start(func_t func)
        {

            for( ; ; )  //死循环
            {
                //4. Server获取新链接
                //sock 是用于和client进行通信的
                struct sockaddr_in peer;
                socklen_t peer_len = sizeof(peer);
                int sock = accept(_listensock,(struct sockaddr*)&peer,&peer_len);
                if(sock < 0)
                {
                    logMessage(ERROR,"accept error,next");
                    continue;
                }
                logMessage(NORMAL,"accept a new link success sock:%d",sock);
            
                //5. 未来通信就用这个sock，面向字节流的，后面全是文件操作                
                // //version 2.1 多进程版
                pid_t id = fork();
                if(id == 0) //子进程
                {
                    close(_listensock);
                    if(fork() > 0) exit(0); //让孙子进程执行代码，子进程退出被父进程回收，孙子进程会变成孤儿进程

                    // serviceIO(sock);
                    handlerEnter(sock,func);
                    close(sock);
                    exit(0);
                }
                //父进程
                pid_t ret = waitpid(id,nullptr,0);
                close(sock);
                if(ret > 0)
                {
                    logMessage(NORMAL,"wait child success");
                }
                // //------------------------------------------------------------------------------------
                // //version 2.2 多进程版 信号方式
                // signal(SIGCHLD,SIG_IGN);    //信号忽略，忽略对子进程的管理

                // pid_t id = fork();
                // if(id == 0) //子进程
                // {
                //     close(_listensock);

                //     serviceIO(sock);
                //     close(sock);
                //     exit(0);
                // }
                // close(sock);

            }
        }
           
        ~calServer()
        {}
    private:
        int _listensock;    //不是用来数据通信的，它是监听链接是否到来的，用于获取新链接的
        uint16_t _port;
    } ;
    
}//namespace end Server 
